package com.ruijie.acl.service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;

import org.hibernate.Criteria;
import org.hibernate.SQLQuery;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;
import org.springframework.util.Assert;

import com.ruijie.acl.AclDevice;
import com.ruijie.emp.components.deviceselector.TempDevice;
import com.ruijie.emp.components.deviceselector.service.DeviceSelectorServiceImpl;
import com.ruijie.emp.device.Device;
import com.ruijie.emp.system.DeviceModel;
import com.ruijie.emp.system.DeviceVendor;
import com.ruijie.emp.system.role.internal.UserRoleUtil;
import com.ruijie.emp.system.role.type.PurviewEnum;
import com.ruijie.foundation.bo.EntityObject;
import com.ruijie.foundation.dao.support.Page;
import com.ruijie.foundation.utils.CollectionUtils;
import com.ruijie.foundation.utils.StringUtils;

/**
 * <p>
 * Title: 设备选择服务实现类
 * </p>
 * <p>
 * Description: Function Description
 * </p>
 * <p>
 * Copyright: Copyright (c) 2008
 * </p>
 * <p>
 * Company: Ruijie Co., Ltd.
 * </p>
 * <p>
 * Create Time: Dec 4, 2008
 * </p>
 * 
 * @author lusl
 *         <p>
 *         Update Time:
 *         </p>
 *         <p>
 *         Updater:
 *         </p>
 *         <p>
 *         Update Comments:
 *         </p>
 */
public class AclDeviceSelectorServiceImpl extends DeviceSelectorServiceImpl {

	@SuppressWarnings("unchecked")
	public List<Device> queryAllSelectedDevices(String uuid) {
		Assert.notNull(uuid);
		Criteria criteria = createCriteria(Device.class);
		criteria.addOrder(Order.asc("id"));

		DetachedCriteria subselect = DetachedCriteria
				.forClass(TempDevice.class);
		subselect.setProjection(Property.forName("real.id"));
		subselect.add(Restrictions.eq("uuid", uuid));
		
		criteria.add(Property.forName("id").in(subselect));
		
		DetachedCriteria subSelectCriteria = this.getSubSelect();
		
		if (subSelectCriteria != null){
			criteria.add(Property.forName("id").in(subSelectCriteria));
		}
		
		//--------------add by sinyee ----------------------------
		criteria.add(Restrictions.sqlRestriction(UserRoleUtil.getSQLNoAnd("this_", "device_id")));

		return criteria.list();

	}

	public Page pagedQueryAvailableDevices(String uuid, Device example,
			Set<DeviceVendor> allowedDeviceVendors,
			Set<DeviceModel> allowedDeviceModels, Criterion criterion,
			int pageNo, int pageSize, String sortOrders, String sortBy) {
		Assert.notNull(example);

		if (CollectionUtils.isEmpty(allowedDeviceVendors)
				&& CollectionUtils.isEmpty(allowedDeviceModels))
			return pagedQueryAvailableDevices(uuid, example, criterion, pageNo,
					pageSize, sortOrders, sortBy);

		return pagedQueryAvailableDevicesWithAllowedDeviceModels(uuid, example,
				allowedDeviceVendors, allowedDeviceModels, criterion, pageNo,
				pageSize, sortOrders, sortBy);
	}

	private Page pagedQueryAvailableDevicesWithAllowedDeviceModels(String uuid,
			Device example, Set<DeviceVendor> allowedDeviceVendors,
			Set<DeviceModel> allowedDeviceModels, Criterion criterion,
			int pageNo, int pageSize, String sortOrders, String sortBy) {
		Assert.notNull(example);

		Criteria criteria = createCriteria(Device.class);

		DetachedCriteria subSelectCriteria = this.getSubSelect();
		
		if (subSelectCriteria != null){
			criteria.add(Property.forName("id").in(subSelectCriteria));
		}
		
		if (StringUtils.hasText(example.getName()))
			criteria.add(Restrictions.like("name", example.getName(),
					MatchMode.ANYWHERE).ignoreCase());

		if (StringUtils.hasText(example.getIp()))
			criteria.add(Restrictions.like("ip", example.getIp(),
					MatchMode.ANYWHERE));

		final List<Long> dmIdList = getIdList(allowedDeviceModels);
		final DeviceModel selectedDeviceModel = example.getDeviceModel();

		boolean deviceModelCriteria = false;
		if (!CollectionUtils.isEmpty(dmIdList) || selectedDeviceModel != null) {
			if (null != selectedDeviceModel
					&& StringUtils.hasText(selectedDeviceModel.getName())) {
				deviceModelCriteria = true;
				criteria.createAlias("deviceModel", "model");
				// 选择的设备型号不在允许的型号之列，直接返回空页
				if (!CollectionUtils.isEmpty(dmIdList)
						&& !likeContain(allowedDeviceModels,
								selectedDeviceModel.getName()))
					return new Page();
				else {
					if (CollectionUtils.isEmpty(dmIdList)) {
						criteria.add(Restrictions
								.like("model.name", example.getDeviceModel()
										.getName(), MatchMode.ANYWHERE));
					} else {
						criteria.add(Restrictions.in("model.id", getAllowedIds(
								allowedDeviceModels, selectedDeviceModel
										.getName())));
					}
				}
			} else {
				if (!CollectionUtils.isEmpty(dmIdList)) {
					deviceModelCriteria = true;
					criteria.createAlias("deviceModel", "model");
					criteria.add(Restrictions.in("model.id", dmIdList));
				}
			}
		}

		
		
		final List<Long> dvIdList = getIdList(allowedDeviceVendors);
		if (null != example.getDeviceModel()
				&& null != example.getDeviceModel().getDeviceSeries()
				&& null != example.getDeviceModel().getDeviceSeries()
						.getVendor()) {
			final DeviceVendor selectedDeviceVendor = example.getDeviceModel()
					.getDeviceSeries().getVendor();
			// 选择的设备型号不在允许的型号之列，直接返回空页
			if (!CollectionUtils.isEmpty(dvIdList)) {
				boolean ret = false;
				for (Long id : dvIdList) {
					if (id.equals(selectedDeviceVendor.getId())) {
						ret = true;
					}
				}
				if (!ret) {
					return new Page();
				}
			}
			if (!deviceModelCriteria) {
				deviceModelCriteria = true;
				criteria.createAlias("deviceModel", "model");
			}
			criteria.createAlias("model.deviceSeries", "deviceSeries");
			criteria.createAlias("deviceSeries.vendor", "vendor");
			criteria.add(Restrictions.eq("vendor.id", selectedDeviceVendor
					.getId()));
		} else {
			if (!CollectionUtils.isEmpty(dvIdList)) {
				if (!deviceModelCriteria) {
					deviceModelCriteria = true;
					criteria.createAlias("deviceModel", "model");
				}
				criteria.createAlias("model.deviceSeries", "deviceSeries");
				criteria.createAlias("deviceSeries.vendor", "vendor");
				criteria.add(Restrictions.in("vendor.id", dvIdList));
			}
		}
		
		//----------------- add by sinyee ---------------
		criteria.add(Restrictions.sqlRestriction(UserRoleUtil.getWriteSQLNoAnd("this_", "device_id")));

		if (sortOrders.equals("asc")) {
			if (sortBy.indexOf(".") > 0) {
				String mode = sortBy.substring(0, sortBy.indexOf("."));
				String name = sortBy.substring(sortBy.indexOf(".") + 1, sortBy
						.length());
				if (!deviceModelCriteria) {
					criteria.createCriteria(mode, "model");
				}
				criteria.addOrder(Order.asc("model." + name));
			} else {
				criteria.addOrder(Order.asc(sortBy));
			}
		} else if (sortOrders.equals("desc")) {
			if (sortBy.indexOf(".") > 0) {
				String mode = sortBy.substring(0, sortBy.indexOf("."));
				String name = sortBy.substring(sortBy.indexOf(".") + 1, sortBy
						.length());
				if (!deviceModelCriteria) {
					criteria.createCriteria(mode, "model");
				}
				criteria.addOrder(Order.desc("model." + name));
			} else {
				criteria.addOrder(Order.desc(sortBy));
			}
		}

		criteria.addOrder(Order.asc("id"));

		DetachedCriteria subselect = DetachedCriteria
				.forClass(TempDevice.class);
		subselect.setProjection(Property.forName("real.id"));
		subselect.add(Restrictions.eq("uuid", uuid));

		criteria.add(Property.forName("id").notIn(subselect));

		return pagedQuery(criteria, pageNo, pageSize);
	}
	
	public DetachedCriteria getSubSelect(){
	    DetachedCriteria subselect = DetachedCriteria.forClass(AclDevice.class);
		subselect.setProjection(Property.forName("device.id"));
	    return subselect;
	}

	/**
	 * <p>
	 * Description: 获取指定型号集合中模糊匹配指定型号名的ID集合
	 * </p>
	 * <p>
	 * Create Time: 2008-12-26
	 * </p>
	 * 
	 * @author lusl
	 * @param deviceModels
	 * @param deviceModelName
	 * @return
	 */
	private List<Long> getAllowedIds(Set<DeviceModel> deviceModels,
			String deviceModelName) {
		List<Long> ids = new ArrayList<Long>();

		if (!CollectionUtils.isEmpty(deviceModels)
				&& StringUtils.hasText(deviceModelName)) {
			for (DeviceModel dm : deviceModels) {
				if (dm.getName().indexOf(deviceModelName) != -1)
					ids.add(dm.getId());
			}
		}
		return ids;
	}

	/**
	 * <p>
	 * Description：指定的型号集合是否包含指定型号名（模糊）
	 * </p>
	 * <p>
	 * Create Time: 2008-12-26
	 * </p>
	 * 
	 * @author lusl
	 * @param deviceModels
	 * @param deviceModelName
	 * @return
	 */
	private boolean likeContain(Set<DeviceModel> deviceModels,
			String deviceModelName) {
		return !getAllowedIds(deviceModels, deviceModelName).isEmpty();
	}

	private Page pagedQueryAvailableDevices(String uuid, Device example,
			Criterion criterion, int pageNo, int pageSize, String sortOrders,
			String sortBy) {
		Assert.notNull(example);
		Criteria criteria = createDeviceCriteria(uuid, example, true,
				sortOrders, sortBy);
		if (criterion != null)
			criteria.add(criterion);
		return pagedQuery(criteria, pageNo, pageSize);

	}

	private Criteria createDeviceCriteria(String uuid, Device example,
			boolean queryAvailable, String sortOrders, String sortBy) {
		Criteria criteria = createCriteria(Device.class);

		DetachedCriteria subSelectCriteria = this.getSubSelect();

		if (subSelectCriteria != null){
			criteria.add(Property.forName("id").in(subSelectCriteria));
		}
		
		if (StringUtils.hasText(example.getName()))
			criteria.add(Restrictions.like("name", example.getName(),
					MatchMode.ANYWHERE).ignoreCase());

		if (StringUtils.hasText(example.getIp()))
			criteria.add(Restrictions.like("ip", example.getIp(),
					MatchMode.ANYWHERE));

		boolean deviceModelCriteria = false;
		if (null != example.getDeviceModel()
				&& StringUtils.hasText(example.getDeviceModel().getName())) {
			deviceModelCriteria = true;
			criteria.createAlias("deviceModel", "model");
			criteria.add(Restrictions.like("model.name", example
					.getDeviceModel().getName(), MatchMode.ANYWHERE));
		}

		if (null != example.getDeviceModel()
				&& null != example.getDeviceModel().getDeviceSeries()
				&& null != example.getDeviceModel().getDeviceSeries()
						.getVendor()) {
			if (!StringUtils.hasText(example.getDeviceModel().getName())
					&& !deviceModelCriteria) {
				deviceModelCriteria = true;
				criteria.createAlias("deviceModel", "model");
			}
			criteria.createAlias("model.deviceSeries", "deviceSeries");
			criteria.createAlias("deviceSeries.vendor", "vendor");
			criteria.add(Restrictions.eq("vendor.id", example.getDeviceModel()
					.getDeviceSeries().getVendor().getId()));
			// Criteria dmCriteria = criteria.createCriteria("deviceModel");
			// dmCriteria.createAlias( "deviceModel" , "model" ) ;
			// dmCriteria.createAlias( "model.deviceSeries" , "deviceSeries" ) ;
			// dmCriteria.add(Restrictions.eq("id",
			// example.getDeviceModel().getDeviceSeries().getVendor()));
		}
		
		//------------- add by sinyee -----------------------
		criteria.add(Restrictions.sqlRestriction(UserRoleUtil.getWriteSQLNoAnd("this_", "device_id")));

		if (sortOrders.equals("asc")) {
			if (sortBy.indexOf(".") > 0) {
				String mode = sortBy.substring(0, sortBy.indexOf("."));
				String name = sortBy.substring(sortBy.indexOf(".") + 1, sortBy
						.length());
				if (!deviceModelCriteria) {
					criteria.createCriteria(mode, "model");
				}
				criteria.addOrder(Order.asc("model." + name));
			} else {
				criteria.addOrder(Order.asc(sortBy));
			}
		} else if (sortOrders.equals("desc")) {
			if (sortBy.indexOf(".") > 0) {
				String mode = sortBy.substring(0, sortBy.indexOf("."));
				String name = sortBy.substring(sortBy.indexOf(".") + 1, sortBy
						.length());
				if (!deviceModelCriteria) {
					criteria.createCriteria(mode, "model");
				}
				criteria.addOrder(Order.desc("model." + name));
			} else {
				criteria.addOrder(Order.desc(sortBy));
			}
		}

		criteria.addOrder(Order.asc("id"));

		DetachedCriteria subselect = DetachedCriteria
				.forClass(TempDevice.class);
		subselect.setProjection(Property.forName("real.id"));
		subselect.add(Restrictions.eq("uuid", uuid));

		if (queryAvailable)
			criteria.add(Property.forName("id").notIn(subselect));
		else
			criteria.add(Property.forName("id").in(subselect));

		return criteria;
	}

	/**
	 * <p>
	 * Description: 将集合内的ID组成一个新的LIST
	 * </p>
	 * <p>
	 * Create Time: 2008-12-12
	 * </p>
	 * 
	 * @author lusl
	 * @param allowedDeviceModels
	 * @return
	 */
	private List<Long> getIdList(
			Collection<? extends EntityObject> allowedDeviceModels) {
		List<Long> dmIdList = new ArrayList<Long>();

		if (!CollectionUtils.isEmpty(allowedDeviceModels)) {
			for (EntityObject entity : allowedDeviceModels) {
				dmIdList.add(entity.getId());
			}
		}
		return dmIdList;
	}

	public Page pagedQuerySelectedDevices(String uuid, Device example,
			int pageNo, int pageSize, String sortOrders, String sortBy) {
		Assert.notNull(example);
		Criteria criteria = createDeviceCriteria(uuid, example, false,
				sortOrders, sortBy);

		return pagedQuery(criteria, pageNo, pageSize);

	}

	public void clearData(String uuid) {
		String hql = "delete from TempDevice where uuid = :uuid";
		createQuery(hql).setParameter("uuid", uuid).executeUpdate();
	}

	public Page pagedQuery(Device example, int pageNo, int pageSize) {
		throw new UnsupportedOperationException();
	}

	public List<Device> query(Device example) {
		throw new UnsupportedOperationException();
	}

	public List<Device> queryLike(Device example) {
		throw new UnsupportedOperationException();
	}

	public void remove(Device entity) {
		throw new UnsupportedOperationException();
	}

	public void save(Device entity) {
		throw new UnsupportedOperationException();

	}

	public void update(Device entity) {
		throw new UnsupportedOperationException();
	}

	public void select(String uuid, Long[] ids) {
		for (Long id : ids) {
			TempDevice t = new TempDevice();
			Device d = new Device();

			d.setId(id);
			t.setReal(d);
			t.setUuid(uuid);

			save(t);
		}
	}

	public void selectAll(String uuid, Set<DeviceVendor> allowedDeviceVendors,
			Set<DeviceModel> allowedDeviceModels, Device example,
			String sqlCriterion) {
		String sql = "INSERT INTO ET_DEV_TEMP_SELECTOR (UUID, DEVICE_ID) SELECT :uuid, et_device.DEVICE_ID FROM et_device inner join et_dev_models et_dev_models on et_device.devmodel_id=et_dev_models.devmodel_id "
				+ " inner join et_dev_series as series on series.series_id = et_dev_models.series_id "
				+ " inner join et_dev_vendor as vendor on series.vendor_id = vendor.vendor_id "
				+ " where DEVICE_ID not in (select DEVICE_ID from ET_DEV_TEMP_SELECTOR where UUID = :uuid) and "
				+ " DEVICE_ID in (select DEVICE_ID from at_acl_device) and ";
		if (!CollectionUtils.isEmpty(allowedDeviceVendors)) {
			sql = sql + " vendor.vendor_id in (:dvIdList) and ";
		}

		if (!CollectionUtils.isEmpty(allowedDeviceModels)) {
			sql = sql + " et_dev_models.DEVMODEL_ID in (:dmIdList) and ";
		}

		String where = getWhere(example);

		if (sqlCriterion != null)
			sql = sql + sqlCriterion + " and " + where;
		else
			sql = sql + where;
		
		//----------------- add by sinyee -------------------------
		sql += UserRoleUtil.getWriteSQL("et_device", "DEVICE_ID");

		SQLQuery query = createSQLQuery(sql);
		query.setString("uuid", uuid);

		if (!CollectionUtils.isEmpty(allowedDeviceVendors)) {
			query.setParameterList("dvIdList", getIdList(allowedDeviceVendors));
		}

		if (!CollectionUtils.isEmpty(allowedDeviceModels)) {
			query.setParameterList("dmIdList", getIdList(allowedDeviceModels));
		}

		query.executeUpdate();
	}

	public void unselect(String uuid, Long[] ids) {
		String hql = "delete from TempDevice where uuid = :uuid and real.id in ( :ids )";
		createQuery(hql).setParameter("uuid", uuid)
				.setParameterList("ids", ids).executeUpdate();

	}

	@SuppressWarnings("unchecked")
	public void unselectAll(String uuid, Device example) {
		String sql = "select   et_device.device_id "
				+ "from     et_device inner join et_dev_models et_dev_models on et_device.devmodel_id=et_dev_models.devmodel_id "
				+ " inner join et_dev_series as series on series.series_id = et_dev_models.series_id "
				+ " inner join et_dev_vendor as vendor on series.vendor_id = vendor.vendor_id "
				+ "where "
				+ getWhere(example)
				+ " and  et_device.device_id in (select  et_dev_temp_selector.device_id  "
				+ "from     et_dev_temp_selector "
				+ "where    et_dev_temp_selector.uuid='" + uuid + "')";

		List r = createSQLQuery(sql).list();

		// FIXME 在SNC 1.0中应改为用语句直接删除相关的临时表中的数据,以提高性能
		if (!CollectionUtils.isEmpty(r)) {
			Long[] ids = new Long[r.size()];

			for (int i = 0; i < r.size(); i++) {
				ids[i] = Long.valueOf(String.valueOf(r.get(i)));
			}

			unselect(uuid, ids);
		}
	}

	private String getWhere(Device example) {
		Assert.notNull(example);

		List<String> l = new ArrayList<String>();
		l.add("1=1");

		final String name = example.getName();
		final String ip = example.getIp();

		if (StringUtils.hasText(name))
			l.add("lower(et_device.nname) like '%" + name + "%'");

		if (StringUtils.hasText(ip))
			l.add("et_device.ip like '%" + ip + "%'");

		if (example.getDeviceModel() != null
				&& StringUtils.hasText(example.getDeviceModel().getName()))
			l.add("et_dev_models.nname like '%"
					+ example.getDeviceModel().getName() + "%'");

		if (example.getDeviceModel() != null
				&& example.getDeviceModel().getDeviceSeries() != null
				&& example.getDeviceModel().getDeviceSeries().getVendor() != null
				&& example.getDeviceModel().getDeviceSeries().getVendor()
						.getId() != null)
			l.add("vendor.vendor_id = "
					+ example.getDeviceModel().getDeviceSeries().getVendor()
							.getId());

		return StringUtils.collectionToDelimitedString(l, " and ");
	}
}
